package vip.xiaonuo.modular.business.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import vip.xiaonuo.core.context.login.LoginContextHolder;
import vip.xiaonuo.core.dbs.CurrentDataSourceContext;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.core.pojo.login.SysLoginUser;
import vip.xiaonuo.modular.business.service.StoreInformationService;
import vip.xiaonuo.modular.business.service.ThemeApiService;
import vip.xiaonuo.modular.cache.PoiQueryCache;
import vip.xiaonuo.modular.common.DistanceHelper;
import vip.xiaonuo.modular.common.WdAnalysisConst;
import vip.xiaonuo.modular.manage.biapplication.entity.BiApplication;
import vip.xiaonuo.modular.manage.biapplication.service.BiApplicationService;
import vip.xiaonuo.modular.manage.biindexdata.entity.BiIndexData;
import vip.xiaonuo.modular.manage.biindexdata.mapper.BiIndexDataMapper;
import vip.xiaonuo.modular.manage.biindexdata.param.BiIndexDataParam;
import vip.xiaonuo.modular.manage.biindextype.entity.BiIndexType;
import vip.xiaonuo.modular.manage.biindextype.service.BiIndexTypeService;
import vip.xiaonuo.modular.manage.bioperateddata.entity.BiOperatedData;
import vip.xiaonuo.modular.manage.bioperateddata.param.BiOperatedDataParam;
import vip.xiaonuo.modular.manage.bioperateddata.service.BiOperatedDataService;
import vip.xiaonuo.modular.manage.theme.service.ThemeService;
import vip.xiaonuo.sys.modular.org.service.SysOrgService;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * @Author: liu
 * @Date:2022/9/7
 */
@Service
public class StoreInformationServiceImpl implements StoreInformationService {
    @Resource
    private BiOperatedDataService biOperatedDataService;

    @Resource
    private SysOrgService sysOrgService;

    @Resource
    private ThemeService themeService;

    @Resource
    private ThemeApiService themeApiService;

    @Resource
    private BiApplicationService biApplicationService;

    @Resource
    private BiIndexDataMapper biIndexDataMapper;

    @Resource
    private BiIndexTypeService biIndexTypeService;

    @Resource
    private PoiQueryCache poiQueryCache;

    public Object page(BiOperatedDataParam param){
        SysLoginUser sysLoginUser = LoginContextHolder.me().getSysLoginUser();
        if(!LoginContextHolder.me().isSuperAdmin()){
            param.setUserId(sysLoginUser.getId());
        }
        Object result = biOperatedDataService.page(param);;
        return result;
    }

    @Override
    public List<BiOperatedData> listNoPage(BiOperatedDataParam param) {
        SysLoginUser sysLoginUser = LoginContextHolder.me().getSysLoginUser();
        if(!LoginContextHolder.me().isSuperAdmin()){
            param.setUserId(sysLoginUser.getId());
        }
        String key = "BiOperatedData:"+JSONObject.toJSONString(param);
        JSONObject cacheObject = poiQueryCache.get(key);
        if (cacheObject != null) {
            return (List<BiOperatedData>) cacheObject.get("rows");
        }

        LambdaQueryWrapper<BiOperatedData> wrapper = new LambdaQueryWrapper<>();
//        if(!LoginContextHolder.me().isSuperAdmin()){
//            wrapper.eq(BiOperatedData::getUserId,param.getUserId());
//        }
        String lng1 = param.getLng1();
        String lng2 = param.getLng2();
        String lat1 = param.getLat1();
        String lat2 = param.getLat2();
        if (lng1 != null && lat1 != null) {
            if(lng1.compareTo(lng2)>0){
                param.setLng1(lng2);
                param.setLng2(lng1);
            }
            if(lat1.compareTo(lat2)>0){
                param.setLat1(lat2);
                param.setLat2(lat1);
            }
            wrapper.between(BiOperatedData::getLat,param.getLat1(),param.getLat2());
            wrapper.between(BiOperatedData::getLng,param.getLng1(),param.getLng2());
            param.setProvName(null);
            param.setCityName(null);
            param.setCountryName(null);
        }

        if(StringUtils.isNotEmpty(param.getProvName())){
            wrapper.eq(BiOperatedData::getProvName,param.getProvName());
        }
        if(StringUtils.isNotEmpty(param.getCityName())){
            wrapper.eq(BiOperatedData::getCityName,param.getCityName());
        }
        if(StringUtils.isNotEmpty(param.getCountryName())){
            wrapper.eq(BiOperatedData::getCountryName,param.getCountryName());
        }
        if(StringUtils.isNotEmpty(param.getOrgCode())){
            wrapper.eq(BiOperatedData::getOrgCode,param.getOrgCode());
        }
        HashMap<String, String> imageMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(param.getOrgCodeList())) {
            wrapper.in(BiOperatedData::getOrgCode,param.getOrgCodeList());
            for (String s : param.getOrgCodeList()) {
                LambdaQueryWrapper<BiApplication> w = new LambdaQueryWrapper<>();
                w.eq(BiApplication::getOrgCode,s);
                w.last(" limit 1 ");
                BiApplication one = biApplicationService.getOne(w);
                if (one != null) {
                    imageMap.put(s, one.getImageUrl());
                }
            }
        }
        List<BiOperatedData> result = biOperatedDataService.list(wrapper);
        for (BiOperatedData bi : result) {
            bi.setImageUrl(imageMap.get(bi.getOrgCode()));
        }
        JSONObject r = new JSONObject();
        r.put("rows", result);
        poiQueryCache.put(key,r);
        return result;
    }

    @Override
    public JSONObject storeAroundInfo(BiOperatedDataParam param){
        String storeId = param.getStoreId();
        if(StringUtils.isEmpty(storeId)){
            throw new ServiceException(9,"门店编号不能为空");
        }
        if(StringUtils.isEmpty(param.getYear())){
            throw new ServiceException(9,"年份不能为空");
        }
        // 合并TypeIdList 和 userTypeIdList
        ArrayList<Long> totalTypeIdList = new ArrayList<>();
        if(CollectionUtil.isNotEmpty(param.getTypeIdList())){
            totalTypeIdList.addAll(param.getTypeIdList());
        }
        if(CollectionUtil.isNotEmpty(param.getUserTypeIdList())){
            totalTypeIdList.addAll(param.getUserTypeIdList());
        }
//        List<Long> typeIdList = param.getTypeIdList();
        if (CollectionUtil.isEmpty(totalTypeIdList)) {
            throw new ServiceException(9,"指标名称不能为空");
        }
        if (param.getDistance() == null) {
            param.setDistance(5);
        }

        String key = JSONObject.toJSONString(param);
        JSONObject cacheObject = (JSONObject)poiQueryCache.get(key);
        if (cacheObject != null) {
            return cacheObject;
        }

        LambdaQueryWrapper<BiOperatedData> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BiOperatedData::getStoreId,storeId);
        wrapper.last(" limit 1 ");
        BiOperatedData one = biOperatedDataService.getOne(wrapper);
        if (one == null) {
            throw new ServiceException(9,"门店编号信息不存在");
        }

        HashMap<String,Long> typeNameMap = new HashMap<>();
        List<BiIndexType> indexTypeList = biIndexTypeService.findByIds(totalTypeIdList);
        for (BiIndexType t : indexTypeList) {
            typeNameMap.put(t.getName(),t.getId());
        }
        //根据门店标号查询到经纬度，查询周边5公里的指标数据
        int distance = param.getDistance();
        String[] points = DistanceHelper.getNearbyDistance(new BigDecimal(one.getLng()), new BigDecimal(one.getLat()), distance);
        BiIndexDataParam biIndexDataParam = new BiIndexDataParam();
        biIndexDataParam.setLng1(points[0]);
        biIndexDataParam.setLng2(points[1]);
        biIndexDataParam.setLat1(points[2]);
        biIndexDataParam.setLat2(points[3]);
        biIndexDataParam.setTypeIdList(new ArrayList<>(typeNameMap.values()));
        biIndexDataParam.setYear(param.getYear());
        CurrentDataSourceContext.setDataSourceType(WdAnalysisConst.CLICKHOUSE_DATASOURCE);
        List<BiIndexData> biIndexData = biIndexDataMapper.selectListCustom(biIndexDataParam);
        CurrentDataSourceContext.clearDataSourceType();

        HashMap<Long, List<BiIndexData>> indexDataMap = new HashMap<>();
        for (BiIndexData b : biIndexData) {
            //判断店铺的位置半径是否符合5公里条件
            double d = DistanceHelper.getDistince(DistanceHelper.parseDouble(b.getLng()),DistanceHelper.parseDouble(b.getLat()),
                    DistanceHelper.parseDouble(one.getLng()),DistanceHelper.parseDouble(one.getLat()));
            if(d > distance){
                continue;
            }
            List<BiIndexData> tmpList = indexDataMap.get(b.getTypeId());
            if (tmpList == null) {
                tmpList = new ArrayList<>();
                tmpList.add(b);
                indexDataMap.put(b.getTypeId(), tmpList);
            }else{
                tmpList.add(b);
            }
        }

        JSONObject result = new JSONObject();

        HashMap<String,List<String>> indexChartDefined = new HashMap<>();



        indexChartDefined.put("道路网密度",Arrays.asList("饼图","总网密度km/k㎡","平均网密度km/k㎡","最高网密度km/k㎡","最低网密度km/k㎡"));
        indexChartDefined.put("科教文化区",Arrays.asList("水纹图","总文化区数量","平均文化区数量","最高文化区数量","最低文化区数量"));
        indexChartDefined.put("发达工作区",Arrays.asList("饼图","总工作区数量","平均工作区数量","最高工作区数量","最低工作区数量"));
        indexChartDefined.put("生活服务区",Arrays.asList("水纹图","总服务区数量","平均服务区数量","最高服务区数量","最低服务区数量"));
        indexChartDefined.put("发达商业区",Arrays.asList("饼图","总商业区数量","平均商业区数量","最高商业区数量","最低商业区数量"));
        indexChartDefined.put("政府服务与文旅休闲区",Arrays.asList("水纹图","总文化区数量","平均文化区数量","最高文化区数量","最低文化区数量"));
        indexChartDefined.put("人均绿地面积",Arrays.asList("饼图","总绿地面k㎡","平均绿地面积k㎡","最高绿地面积k㎡","最低绿地面积k㎡"));
        indexChartDefined.put("交通设施",Arrays.asList("水纹图","总设施数量","平均设施数量","最高设施数量","最低设施数量"));
        indexChartDefined.put("传统住宅区",Arrays.asList("饼图","总传统住宅区数量","平均传统住宅数量","最高传统住宅数量","最低住宅数量"));
        indexChartDefined.put("新兴住宅区",Arrays.asList("饼图","总新兴住宅区数量","平均新兴住宅区数量","最高新兴住宅区数量","最低新兴住宅数量"));
        indexChartDefined.put("人口总数",Arrays.asList("水纹图","总人口","平均人口","最高人口","最低人口"));

        LinkedHashMap<String, Object> chart = new LinkedHashMap<>();

        JSONObject sumChart = new JSONObject();
        ArrayList<String> indexNameArray = new ArrayList<>();
        ArrayList<Double> sumArray = new ArrayList<>();

        HashSet<String> histogramIndexNames = new HashSet<>();

        for (String indexName : typeNameMap.keySet()) {
            if(indexName.equals("发达工作区") || indexName.equals("发达商业区")){
                if(typeNameMap.keySet().contains("发达工作区")&& typeNameMap.keySet().contains("发达商业区")){
                    // 如果发达工作区和发达商业区同时存在，则使用“柱状图”对比两个指标
                    histogramIndexNames.add("发达工作区/发达商业区");
                    continue;
                }
            }else if(indexName.equals("传统住宅区") || indexName.equals("新兴住宅区")){
                if(typeNameMap.keySet().contains("传统住宅区")&& typeNameMap.keySet().contains("新兴住宅区")){
                    // 如果传统住宅区和新兴住宅区同时存在，则使用“柱状图”对比两个指标
                    histogramIndexNames.add("发达工作区/发达商业区");
                    continue;
                }
            }
            List<String> chartDefinedList = indexChartDefined.get(indexName);
            String chartType = chartDefinedList.get(0);
            List<String> subList = chartDefinedList.subList(1, chartDefinedList.size());
            JSONObject object = defaultIndexSummary(indexDataMap.get(typeNameMap.get(indexName)), chartType,subList, indexDataMap, typeNameMap);
            chart.put(indexName+"-"+chartDefinedList.get(0), object);
            indexNameArray.add(indexName);
            sumArray.add(object.getDouble("sum"));
        }
        // 如两个指标同时选中，则使用“柱状图”对比两个指标“总值、平均值、最高值、最小值”
        for (String indexName : histogramIndexNames) {
            String[] split = indexName.split("/");
            List<String> xList = Arrays.asList("总值", "平均值", "最高值", "最小值");
            JSONArray yData = new JSONArray();
            for (String name : split) {
                JSONObject j = new JSONObject();
                j.put("name",name);
                List<String> chartDefinedList = indexChartDefined.get(name);
                List<String> subList = chartDefinedList.subList(1, chartDefinedList.size());
                JSONObject object = defaultIndexSummary(indexDataMap.get(typeNameMap.get(name)), "柱状图",subList, indexDataMap, typeNameMap);
                j.put("list", object.get("y"));
                yData.add(j);
            }
            JSONObject element = new JSONObject();
            element.put("xList", xList);
            element.put("yData", yData);
            chart.put(indexName+"-柱状图",element);
        }
        // 当选择“自定义指标”的一级指标时，则统计对各二级分类的数据总数及总数占比
        if (CollectionUtil.isNotEmpty(param.getUserTypeIdList())) {
            HashMap<Long, ArrayList<String>> groupByPidMap = new HashMap<>();
            for (BiIndexType tt : indexTypeList) {
                //只统计用户指标
                if (param.getUserTypeIdList().contains(tt.getId())) {
                    ArrayList<String> names = groupByPidMap.get(tt.getPid());
                    if (names == null) {
                        names = new ArrayList<>();
                        names.add(tt.getName());
                        groupByPidMap.put(tt.getPid(), names);
                    }else{
                        names.add(tt.getName());
                    }
                }
            }
            if (CollectionUtil.isNotEmpty(groupByPidMap)) {
                for (Long tid : groupByPidMap.keySet() ) {
                    ArrayList<String> strings = groupByPidMap.get(tid);
                    if (CollectionUtil.isEmpty(strings) || strings.size()<2) {
                        continue;
                    }
                    List<String> xList = Arrays.asList("总值");
                    JSONArray yData = new JSONArray();
                    for (String name : strings) {
                        JSONObject j = new JSONObject();
                        j.put("name",name);
                        List<String> chartDefinedList = indexChartDefined.get(name);
                        List<String> subList = Arrays.asList("总值");
                        JSONObject object = defaultIndexSummary(indexDataMap.get(typeNameMap.get(name)), "柱状图",subList, indexDataMap, typeNameMap);
                        j.put("list", object.get("y"));
                        yData.add(j);
                    }
                    JSONObject element = new JSONObject();
                    element.put("xList", xList);
                    element.put("yData", yData);
                    BiIndexType byId = biIndexTypeService.getById(tid);
                    chart.put(byId.getName()+"统计数据总数-柱状图",element);
                }
            }

        }

        result.put("title", one.getStoreName());
        result.put("distance", distance);
        result.put("chart", chart);
        poiQueryCache.put(key, result);
        return result;
    }

    private JSONObject defaultIndexSummary(List<BiIndexData> data,String chartType,List<String> chartDefinedList,
                                           HashMap<Long,List<BiIndexData>> indexDataMap,HashMap<String,Long> typeMap){
        JSONObject result = new JSONObject();

        double[] doubles = {0};
        if (data != null) {
            doubles = data.stream().filter(e -> StringUtils.isNotEmpty(e.getValue()))
                    .mapToDouble(e -> Double.parseDouble(e.getValue())).toArray();
        }
        double average = Arrays.stream(doubles).average().getAsDouble();
        double sum = Arrays.stream(doubles).sum();
        result.put("average",new BigDecimal(average).setScale(2,4).doubleValue());
        result.put("sum",new BigDecimal(sum).setScale(2,4).doubleValue());

        if ("水纹图".equals(chartType)) {
            JSONArray array = new JSONArray();
            for (String s : chartDefinedList) {
                JSONObject j = new JSONObject();
                j.put("name",s);
                double value = 0;
                if (s.contains("平均")) {
                    value = average;
                }else if (s.contains("最高")) {
                    value = Arrays.stream(doubles).max().getAsDouble();
                }else if (s.contains("最低")) {
                    value = Arrays.stream(doubles).min().getAsDouble();
                }else if (s.contains("总")) {
                    value = sum;
                }
                j.put("value",new BigDecimal(value).setScale(2,4).doubleValue());
                array.add(j);
            }
            result.put("w", array);
            result.put("sum", array.stream().mapToDouble(e -> ((JSONObject) e).getDouble("value")).sum());
        }else if ("饼图".equals(chartType)) {
            JSONArray array = new JSONArray();
            for (String s : chartDefinedList) {
                JSONObject j = new JSONObject();
                j.put("name",s);
                double value = 0;
                if (s.contains("平均")) {
                    value = average;
                }else if (s.contains("最高")) {
                    value = Arrays.stream(doubles).max().getAsDouble();
                }else if (s.contains("最低")) {
                    value = Arrays.stream(doubles).min().getAsDouble();
                }else if (s.contains("总")) {
                    value = sum;
                }
                j.put("value",new BigDecimal(value).setScale(2,4).doubleValue());
                array.add(j);
            }
            result.put("z", array);
            result.put("sum", array.stream().mapToDouble(e -> ((JSONObject) e).getDouble("value")).sum());
        } else if ("柱状图".equals(chartType)) {
            List<Double> y = new ArrayList<>();
            for (String s : chartDefinedList) {
                if (s.contains("平均")) {
                    y.add(new BigDecimal(average).setScale(2,4).doubleValue());
                }else if (s.contains("最高")) {
                    y.add(new BigDecimal(Arrays.stream(doubles).max().getAsDouble()).setScale(2,4).doubleValue());
                }else if (s.contains("最低")) {
                    y.add(new BigDecimal(Arrays.stream(doubles).min().getAsDouble()).setScale(2,4).doubleValue());
                }else if (s.contains("总")) {
                    y.add(new BigDecimal(sum).setScale(2,4).doubleValue());
                }
            }
            result.put("x", chartDefinedList);
            result.put("y", y);
            result.put("max", new BigDecimal(y.get(0)).setScale(-1,BigDecimal.ROUND_UP).intValue());
        }else{
            throw new ServiceException(9,"defaultIndexSummary type error");
        }
        return result;
    }
}
